package com.lagou.edu.factory;

import com.lagou.edu.annonation.*;
import com.lagou.edu.service.impl.TransferServiceImpl;
import com.lagou.edu.utils.ClassUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
@ComponentScan({"com.lagou.edu.service.impl", "com.lagou.edu.dao.impl", "com.lagou.edu.utils","com.lagou.edu.factory"})
@EnableTransactionManagement
public class AnnonationBeanFactory {

    /**
     * 任务一：扫描包名下面所有的类，并把配置有@service @Component 的类注入容器
     * 任务二：实例化容器里面带有@Autowired 的属性
     * 任务三：扫描配置@Service的类，class或者method 配置有@Transactional 注解，则注入代理类
     */

    private static Map<String, Object> map = new HashMap<>();  // 存储对象


    private static Boolean openTransactional(Class clazz) {
        EnableTransactionManagement enableTransaction = AnnonationBeanFactory.class.getAnnotation(EnableTransactionManagement.class);

        if(enableTransaction==null){
            return Boolean.FALSE;
        }

        if (clazz.getAnnotation(Transactional.class) != null) return Boolean.TRUE;
        for (Method method : Arrays.asList(clazz.getMethods())) {
            if (method.getAnnotation(Transactional.class) != null) {
                return Boolean.TRUE;
            }
        }

        return Boolean.FALSE;
    }


    static {
        ComponentScan annotation = AnnonationBeanFactory.class.getAnnotation(ComponentScan.class);

        String[] packageArr = annotation.value();

        Set<Class> classes = new HashSet<>();

        Arrays.asList(packageArr).stream().forEach(pack -> classes.addAll(ClassUtil.getClasses(pack)));

        classes.stream().filter(clazz -> clazz.getAnnotation(Service.class) != null).forEach(clazz -> {
            Service service = (Service) clazz.getAnnotation(Service.class);
            String value = service != null ? service.value() : "";

            String id = value.isEmpty() ? ClassUtil.getBeanId(clazz) : value;
            try {
                map.put(id, clazz.newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });

        classes.stream().filter(clazz -> clazz.getAnnotation(Component.class) != null).forEach(clazz -> {
            Component repository = (Component) clazz.getAnnotation(Component.class);
            String value = repository != null ? repository.value() : "";

            String id = value.isEmpty() ? ClassUtil.getBeanId(clazz) : value;
            try {
                map.put(id, clazz.newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });


        map.values().stream().forEach(bean -> {
            Class<?> aClass = bean.getClass();
            Arrays.asList(aClass.getDeclaredFields()).stream().filter(field -> field.isAnnotationPresent(Autowired.class)).forEach(field -> {
                field.setAccessible(Boolean.TRUE);
                try {
                    String name = field.getName();
                    Method method = aClass.getMethod("set" + name.substring(0, 1).toUpperCase() + name.substring(1, name.length()), field.getType());

                    method.invoke(bean, getBean(field.getAnnotation(Autowired.class).value()));
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
        });


        ProxyFactory proxyFactory = (ProxyFactory) getBean("proxyFactory");

        //装备代理对象SS
        classes.stream().filter(clazz -> clazz.getAnnotation(Service.class) != null).forEach(clazz -> {
            Service service = (Service) clazz.getAnnotation(Service.class);
            String value = service != null ? service.value() : "";

            String id = value.isEmpty() ? ClassUtil.getBeanId(clazz) : value;
            if (openTransactional(clazz)) {
                map.put(id, proxyFactory.getProxy(getBean(id)));
            }
        });

    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }

    public static void main(String[] args) {
//        String name="service";
//        name="set"+name.substring(0,1).toUpperCase()+name.substring(1,name.length());
//        System.out.println(name);

        Class clazz = TransferServiceImpl.class;
//        Arrays.asList(clazz.getDeclaredFields()).stream().forEach(f-> System.out.println(f.getName()));
//        System.out.println(clazz.getInterfaces());
        System.out.println(clazz.isInterface() || Proxy.isProxyClass(clazz));
        System.out.println(clazz.isInterface());
    }

}
